package com.mrlv.common.exception;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.mrlv.common.enums.ResultCodeEnum;
import com.mrlv.common.wrapper.ResultMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.Assert;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * SpringMVC统一异常处理
 * @author Mrlv
 * @date 2021年12月19日 11:47
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理业务校验过程中碰到的非法参数异常 该异常基本由{@link org.springframework.util.Assert}抛出
     * @see Assert#hasLength(String, String)
     * @see Assert#hasText(String, String)
     * @see Assert#isTrue(boolean, String)
     * @see Assert#isNull(Object, String)
     * @see Assert#notNull(Object, String)
     * @see Assert#state(boolean, String)
     * @param exception 参数校验异常
     * @return API返回结果对象包装后的错误输出结果
     */
    @ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultMsg handleIllegalArgumentException(RuntimeException exception) {
        log.error("非法参数,ex = {}", exception.getMessage(), exception);
        return ResultMsg.createByErrorCodeMessage(ResultCodeEnum.INVALID_PARAM.getCode(), exception.getMessage());
    }



    /**
     * 忽略参数异常处理器
     *
     * @param e 忽略参数异常
     * @return Result
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResultMsg parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
        log.error("", e);
        return ResultMsg.createByErrorCodeMessage(ResultCodeEnum.INVALID_PARAM.getCode(), "请求参数 " + e.getParameterName() + " 不能为空");
    }

    /**
     * 缺少请求体异常处理器
     *
     * @param e 缺少请求体异常
     * @return ResponseResult
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResultMsg parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        log.error("", e);
        return ResultMsg.createResult(ResultCodeEnum.INVALID_PARAM);
    }


//    @ExceptionHandler(MasterException.class)
//    @ResponseBody
//    public ResultMsg exceptionHandler(HttpServletRequest request, MasterException exception){
//        log.error("请求 =====》{}  接口异常 error:{}", request.getRequestURI(), ExceptionUtil.getMessage(exception));
//        return ResultMsg.createByErrorCodeMessage(exception.getCode(), exception.getMessage());
//    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResultMsg exceptionHandler(HttpServletRequest request, Exception exception){
        log.error("请求 ====》{}  接口异常 error:{}", request.getRequestURI(), ExceptionUtil.getMessage(exception));
        return ResultMsg.createByErrorCodeMessage(ResultCodeEnum.SYSTEM_ERR.getCode(), "系统繁忙，请稍后重试");
    }

    /**
     * Validated 校验
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResultMsg ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
        List<String> msgList = new ArrayList<>();
        while (iterator.hasNext()) {
            ConstraintViolation<?> cvl = iterator.next();
            msgList.add(cvl.getMessageTemplate());
        }
        return ResultMsg.createResult(ResultCodeEnum.INVALID_PARAM.getCode(), msgList);
    }

}
